# -- coding: utf-8 --

import sys
import threading
import msvcrt
import numpy as np
from ctypes import *

import math
import cv2
sys.path.append("./MVSCam")
from MvCameraControl_class import *


deviceList = MV_CC_DEVICE_INFO_LIST()
tlayerType = MV_GIGE_DEVICE | MV_USB_DEVICE
aaa = []
def cap_num():
    # ch:枚举设备 | en:Enum device
    ret = MvCamera.MV_CC_EnumDevices(tlayerType, deviceList)
    if ret != 0:
        print ("enum devices fail! ret[0x%x]" % ret)
        return 0

    if deviceList.nDeviceNum == 0:
        print ("find no device!")
        return 0

    print ("Find %d devices!" % deviceList.nDeviceNum)

    for i in range(0, deviceList.nDeviceNum):
        mvcc_dev_info = cast(deviceList.pDeviceInfo[i], POINTER(MV_CC_DEVICE_INFO)).contents
        if mvcc_dev_info.nTLayerType == MV_GIGE_DEVICE:
            print ("\ngige device: [%d]" % i)
            strModeName = ""
            for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chModelName:
                strModeName = strModeName + chr(per)
            print ("device model name: %s" % strModeName)

            nip1 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24)
            nip2 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16)
            nip3 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8)
            nip4 = (mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff)
            ip = "%d.%d.%d.%d" % (nip1, nip2, nip3, nip4)
            aaa.append(ip)
            print ("current ip: %d.%d.%d.%d\n" % (nip1, nip2, nip3, nip4))
        elif mvcc_dev_info.nTLayerType == MV_USB_DEVICE:
            print ("\nu3v device: [%d]" % i)
            strModeName = ""
            for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chModelName:
                if per == 0:
                    break
                strModeName = strModeName + chr(per)
            print ("device model name: %s" % strModeName)

            strSerialNumber = ""
            for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chSerialNumber:
                if per == 0:
                    break
                strSerialNumber = strSerialNumber + chr(per)
            print ("user serial number: %s" % strSerialNumber)
    
    return deviceList.nDeviceNum


class MVSCam:
    
    def __init__(self):
        self.num = cap_num()

    def open(self, nConnectionNum):
        self.cam = None
        if nConnectionNum>=self.num:
            return False
        #nConnectionNum = input("please input the number of the device to connect:")
        
        if int(nConnectionNum) >= deviceList.nDeviceNum:
            print ("intput error!")
            return False

        # ch:创建相机实例 | en:Creat Camera Object
        cam = MvCamera()
        
        # ch:选择设备并创建句柄 | en:Select device and create handle
        stDeviceList = cast(deviceList.pDeviceInfo[int(nConnectionNum)], POINTER(MV_CC_DEVICE_INFO)).contents

        ret = cam.MV_CC_CreateHandle(stDeviceList)
        if ret != 0:
            print ("create handle fail! ret[0x%x]" % ret)
            return False

        # ch:打开设备 | en:Open device
        ret = cam.MV_CC_OpenDevice(MV_ACCESS_Exclusive, 0)
        if ret != 0:
            print ("open device fail! ret[0x%x]" % ret)
            return False
        
        # ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
        if stDeviceList.nTLayerType == MV_GIGE_DEVICE:
            nPacketSize = cam.MV_CC_GetOptimalPacketSize()
            if int(nPacketSize) > 0:
                ret = cam.MV_CC_SetIntValue("GevSCPSPacketSize",nPacketSize)
                if ret != 0:
                    print ("Warning: Set Packet Size fail! ret[0x%x]" % ret)
            else:
                print ("Warning: Get Packet Size fail! ret[0x%x]" % nPacketSize)

        # ch:设置触发模式为off | en:Set trigger mode as off
        ret = cam.MV_CC_SetEnumValue("TriggerMode", MV_TRIGGER_MODE_OFF)
        if ret != 0:
            print ("set trigger mode fail! ret[0x%x]" % ret)
            return False

        # ch:获取数据包大小 | en:Get payload size
        stParam =  MVCC_INTVALUE()
        memset(byref(stParam), 0, sizeof(MVCC_INTVALUE))
        
        ret = cam.MV_CC_GetIntValue("PayloadSize", stParam)
        if ret != 0:
            print ("get payload size fail! ret[0x%x]" % ret)
            return False
        nPayloadSize = stParam.nCurValue

        # ch:开始取流 | en:Start grab image
        ret = cam.MV_CC_StartGrabbing()
        if ret != 0:
            print ("start grabbing fail! ret[0x%x]" % ret)
            return False

        data_buf = (c_ubyte * nPayloadSize)()

        self.pData = byref(data_buf)
        self.nDataSize = nPayloadSize
        stFrameInfo = MV_FRAME_OUT_INFO_EX()
        memset(byref(stFrameInfo), 0, sizeof(stFrameInfo))
        self.cam = cam
        self.stFrameInfo = stFrameInfo
        self.data_buf = data_buf
        return True

    def getFrame(self):
        if self.cam is None:
            return None
        cam = self.cam
        pData = self.pData
        nDataSize = self.nDataSize
        stFrameInfo = self.stFrameInfo
        ret = cam.MV_CC_GetOneFrameTimeout(pData, nDataSize, stFrameInfo, 500)

        if ret == 0:
            #print ("get one frame: Width[%d], Height[%d], nFrameNum[%d]"  % (stFrameInfo.nWidth, stFrameInfo.nHeight, stFrameInfo.nFrameNum))
            pass
        else:
            print ("no data[0x%x]" % ret)
            return None
        
        cn = nDataSize/(stFrameInfo.nHeight*stFrameInfo.nWidth)
        cn = int(math.ceil(cn))
        npArray = np.zeros((stFrameInfo.nHeight, stFrameInfo.nWidth, cn), dtype=np.uint8)
        npArrayPtr = npArray.ctypes.data_as(POINTER(c_ubyte))
        memmove(npArrayPtr, pData, nDataSize)
        if PixelType_Gvsp_YUV422_YUYV_Packed==stFrameInfo.enPixelType:
            #print(cv2.COLOR_YUV2BGR_YUYV)
            #print(cv2.COLOR_YUV2BGR_Y422)
            npArray = cv2.cvtColor(npArray, cv2.COLOR_YUV2BGR_YUYV)

        return npArray

    def stop(self):
        if self.cam is None:
            return 0
        cam = self.cam
        data_buf = self.data_buf
        #msvcrt.getch()
        # ch:停止取流 | en:Stop grab image
        ret = cam.MV_CC_StopGrabbing()
        if ret != 0:
            print ("stop grabbing fail! ret[0x%x]" % ret)
            del data_buf
            #sys.exit()

        # ch:关闭设备 | Close device
        ret = cam.MV_CC_CloseDevice()
        if ret != 0:
            print ("close deivce fail! ret[0x%x]" % ret)
            del data_buf
            #sys.exit()

        # ch:销毁句柄 | Destroy handle
        ret = cam.MV_CC_DestroyHandle()
        if ret != 0:
            print ("destroy handle fail! ret[0x%x]" % ret)
            del data_buf
            #sys.exit()

        del data_buf
        return 1

def test_MVSCam():
    cam = MVSCam()
    if cam.open(2):
        for i in range(10):
            im = cam.getFrame()
            if im is None:
                print('data is None')
                break
            im = cv2.resize(im, (640, 480))
            cv2.imshow('im', im)
            print(i)
            cv2.waitKey(10)

        cam.stop()
    
    print('end')

if __name__ == "__main__":
    test_MVSCam()